package dfxnftables

import (
	"context"
	"fmt"

	"github.com/google/nftables"
)

type Nftables struct {
	NfMeta
}
// CreateTables 创建一个 nftables 表（如果它尚不存在）。
// 它首先验证元数据，检查现有表，
// 如果需要则添加一个新表。
//
// 参数:
//   - ctx: 用于取消和超时的上下文。
//   - c: 到 nftables 子系统的连接。
//
// 返回值:
//   - 如果验证或表创建失败，则返回错误；否则返回 nil。
func (n *Nftables) CreateTables(ctx context.Context, c *nftables.Conn) error {
	if err := n.NfMeta.Validate(); err != nil {
		return err
	}
	fam := n.Family()
	// 检查是否已存在
	tabs, err := c.ListTables()
	if err != nil {
		return err
	}
	for _, t := range tabs {
		if t.Family == fam && t.Name == n.TableName {
			return nil
		}
	}
	// 创建新表
	c.AddTable(n.Table())

	if err := c.Flush(); err != nil {
		return fmt.Errorf("添加表后刷新失败: %w", err)
	}
	return nil
}

// CheckTables 检查指定的 nftables 表是否存在。
//
// 参数:
//   - ctx: 用于取消和超时的上下文。
//   - c: 到 nftables 子系统的连接。
//
// 返回值:
//   - 如果表存在则返回 true，否则返回 false。
//   - 如果验证或列出表失败，则返回错误；否则返回 nil。
func (n *Nftables) CheckTables(ctx context.Context, c *nftables.Conn) (bool, error) {
	if err := n.NfMeta.Validate(); err != nil {
		return false, err
	}
	fam := n.Family()
	tabs, err := c.ListTables()
	if err != nil {
		return false, err
	}
	for _, t := range tabs {
		if t.Family == fam && t.Name == n.TableName {
			return true, nil
		}
	}
	return false, nil
}

// QueryTables 返回给定地址族中所有表名的列表。
//
// 参数:
//   - ctx: 用于取消和超时的上下文。
//   - c: 到 nftables 子系统的连接。
//
// 返回值:
//   - 包含匹配表名的字符串切片。
//   - 如果验证或列出表失败，则返回错误；否则返回 nil。
func (n *Nftables) QueryTables(ctx context.Context, c *nftables.Conn) ([]string, error) {
	if err := n.NfMeta.Validate(); err != nil {
		return nil, err
	}
	fam := n.Family()
	tabs, err := c.ListTables()
	if err != nil {
		return nil, err
	}
	var names []string
	for _, t := range tabs {
		if t.Family == fam {
			names = append(names, t.Name)
		}
	}

	return names, nil
}

// QueryTableshandle 检索指定表的句柄（指针）。
//
// 参数:
//   - ctx: 用于取消和超时的上下文。
//   - c: 到 nftables 子系统的连接。
//
// 返回值:
//   - 如果找到，返回指向 nftables.Table 对象的指针。
//   - 如果验证或查找失败，或表未找到，则返回错误。
func (n *Nftables) QueryTableshandle(ctx context.Context, c *nftables.Conn) (*nftables.Table, error) {
	if err := n.NfMeta.Validate(); err != nil {
		return nil, err
	}
	fam := n.Family()
	tabs, err := c.ListTables()
	if err != nil {
		return nil, err
	}
	for _, t := range tabs {
		if t.Family == fam && t.Name == n.TableName {
			return t, nil
		}
	}
	return nil, fmt.Errorf("表 %s (%s) 未找到", n.TableName, n.AddressFamily)
}

// DeleteTables 删除指定的 nftables 表（如果存在）。
//
// 参数:
//   - ctx: 用于取消和超时的上下文。
//   - c: 到 nftables 子系统的连接。
//
// 返回值:
//   - 如果验证、删除或刷新失败，则返回错误；否则返回 nil。
func (n *Nftables) DeleteTables(ctx context.Context, c *nftables.Conn) error {
	if err := n.NfMeta.Validate(); err != nil {
		return err
	}
	fam := n.Family()
	tabs, err := c.ListTables()
	if err != nil {
		return err
	}
	for _, t := range tabs {
		if t.Family == fam && t.Name == n.TableName {
			c.DelTable(t)
			if err := c.Flush(); err != nil {
				return fmt.Errorf("删除表后刷新失败: %w", err)
			}
			break
		}
	}
	return nil
}

// FlushTables 清除指定表中的所有链、集合和规则。
//
// 参数:
//   - ctx: 用于取消和超时的上下文。
//   - c: 到 nftables 子系统的连接。
//
// 返回值:
//   - 如果验证、刷新操作或最终刷新失败，则返回错误；否则返回 nil。
func (n *Nftables) FlushTables(ctx context.Context, c *nftables.Conn) error {
	if err := n.NfMeta.Validate(); err != nil {
		return err
	}
	fam := n.Family()
	tabs, err := c.ListTables()
	if err != nil {
		return err
	}
	for _, t := range tabs {
		if t.Family == fam && t.Name == n.TableName {
			// 直接刷新表（清空其中的 chain/set/rule）
			c.FlushTable(t)
			if err := c.Flush(); err != nil {
				return fmt.Errorf("刷新表后刷新失败: %w", err)
			}
			break
		}
	}
	return nil
}